home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-12-18 | 29.5 KB | 1,072 lines |
- /**************************************************************************
- * CLASS: MiscDragView
- * Copyright (C) 1995 Robert Todd Thomas
- * Use is governed by the MiscKit license
- *
- * See the header file for more information on this class.
- *
- * This object is included in the MiscKit by permission from the author
- * and its use is governed by the MiscKit license, found in the file
- * "LICENSE.rtf" in the MiscKit distribution. Please refer to that file
- * for a list of all applicable permissions and restrictions.
- **************************************************************************/
-
- #import <misckit/MiscBase.h>
- #import "MiscDragView-Delegate.h"
- #import "MiscDragView.h"
-
- // Since you can only conceivably have one drag going on at once,
- // I made this a class var. You can access it from subclasses through
- // setDragImage: and dragImage.
- static id sourceDragImage = nil;
-
- // This image is for the "ghost" image we will display if we are the
- // destination view.
- static id destDragImage = nil;
- static NXSize ddiSize = {0.0, 0.0};
-
- // Used for shadowing images in the view.
- static id sourceDragView = nil;
- static id destinationDragView = nil;
-
- /*
- * A proper implementation of versioning. If you add ivars to the class (or
- * just want to dork with the reading/writing) check out the comments tagged
- * "Archiving: READ ME". BJM 5/24/94, adjusted 6/17/94.
- */
-
- /*
- * **** Archiving: READ ME **** This is the current and defined version of the
- * class. It is used to identify what data will be written and how that will
- * happen. If the read/write stuff is modified AT ALL, this must be bumped up
- * (I always bump by one) and the other comments must be followed. Failure to
- * do so will result in palettes and nibs that cannot be read. BJM 5/24/94
- */
- #define MISC_DRAG_VIEW_VERSION 3
-
- @implementation MiscDragView
-
- + initialize
- {
- if (self == [MiscDragView class])
- {
- /*
- * **** Archiving: READ ME **** After bumping the _VERSION, it is
- * considered common practice to add a comment line indicating the new
- * version number, date, and modifier. Optionally, the reason for the
- * change. There is no need to modify the setVersion message. BJM
- * 5/24/94
- */
- // version 0: initial. (bjm)
- // version 1: add target/action support (Steve_Hayman@Objectario.com)
- // version 2: add accepting image (e.g. opening folder)
- [[MiscDragView class] setVersion:MISC_DRAG_VIEW_VERSION];
- }
-
- return self;
- }
-
-
-
- - initFrame: (const NXRect *)frameRect
- {
- [super initFrame: frameRect];
- [self initDragTypes];
- [self setAllowSourceDragging: YES];
- [self setAllowDestinationDragging: YES];
- freeWhenDragDone = NO;
- [self setBorderType: NX_BEZEL];
- theImage = theAcceptingImage = nil;
- [self setDelegate: nil];
- [self setShadowIncoming:YES];
- [self setTarget:nil];
- [self setDragImageIsMyImage:YES];
- return self;
- }
-
-
-
- - initDragTypes
- {
- // Override this method in subclasses to define what drag types you
- // want to allow.
- if ([delegate respondsTo: @selector(initDragTypes:)])
- [delegate initDragTypes:self];
- return self;
- }
-
-
-
- - free
- {
- if (theImage != nil)
- [theImage free];
-
- return [super free];
- }
-
-
-
- - setImage: (NXImage *)newImage
- {
- // I'm not sure if delaying the freeing of the image is necessary,
- // but better safe than sorry.
- if (theImage != nil)
- [self perform: @selector(_freeImage:) with: theImage
- afterDelay: 0.0 cancelPrevious: NO];
-
- // Setup the new image. If newImage is nil, the view will be cleared.
- theImage = newImage;
-
- if (theImage != nil)
- {
- [theImage getSize: &imageSize];
- [theImage setScalable: YES];
- [theImage setDataRetained:YES];
- }
- else
- {
- imageSize.width = 0.0;
- imageSize.height = 0.0;
- }
-
- [self displayFromOpaqueAncestor:(NXRect *)0 :0 :NO];
- return self;
- }
-
-
- - setAcceptingImage: (NXImage *)newImage
- {
- // I'm not sure if delaying the freeing of the image is necessary,
- // but better safe than sorry.
- if (theImage != nil)
- [self perform: @selector(_freeImage:) with: theAcceptingImage
- afterDelay: 0.0 cancelPrevious: NO];
-
- // Setup the new image. If newImage is nil, the view will be cleared.
- theAcceptingImage = newImage;
- [self setShadowIncoming:NO];
- return self;
- }
- - setImageByName: (const char*)newImageName
- { return [self setImage:[NXImage findImageNamed:newImageName]];
- }
- - setAcceptingImageByName: (const char*)newImageName
- { return [self setAcceptingImage:[NXImage findImageNamed:newImageName]];
- }
- -(const char*) imageName
- { return [theImage name];
- }
- -(const char*) acceptingImageName
- { return [theAcceptingImage name];
- }
-
- - setImageByFilename: (const char *)aFilename
- {
- // If you pass a NULL for filename it will clear the image.
- if (aFilename != NULL && strlen(aFilename) > 0)
- [self setImage: [ [NXImage alloc] initFromFile: aFilename] ];
- else
- [self setImage:nil];
-
- return self;
- }
-
-
-
- - (NXImage *)image
- {
- // Returns the image currently displayed in the view.
- return theImage;
- }
-
- - (NXImage *)acceptingImage
- {
- // Returns the image currently displayed in the view.
- return theAcceptingImage;
- }
-
-
-
- - setDragImage: (NXImage *)anImage
- {
- // Set the image that is to be dragged. You are responsible for
- // freeing the image when you are done with it (if you allocated
- // it yourself).
- [self setDragImage: anImage freeWhenDone: NO];
- if(anImage != nil) [self setDragImageIsMyImage:NO];
- return self;
- }
-
-
-
- - setDragImage: (NXImage *)anImage freeWhenDone: (BOOL)freeIt
- {
- // Use if you would like MiscDragView to take care of freeing
- // the dragImage when the drag is complete.
-
- sourceDragImage = anImage;
- freeWhenDragDone = freeIt;
- return self;
- }
-
-
-
- - (NXImage *)dragImage
- {
- return dragImageIsMyImage?theImage:sourceDragImage;
- }
-
-
-
- - setBorderType: (int)aType
- {
- // Border Type can be one of NX_BEZEL, NX_GROOVE, NX_LINE, or NX_NOBORDER,
- // same as the appkit's Box.
- border = aType;
- [self displayFromOpaqueAncestor:(NXRect *)0 :0 :NO];
- return self;
- }
-
-
-
- - (int)borderType
- {
- return border;
- }
-
-
-
- - setAllowSourceDragging: (BOOL)aBool
- {
- // Sets whether you would like your view to begin a source drag.
- allowSourceDragging = aBool;
- return self;
- }
-
-
-
- - (BOOL)allowSourceDragging
- {
- // If YES is returned, the view can behave as the source of dragging,
- // NO if it cannot.
- return allowSourceDragging;
- }
-
-
-
- - setAllowDestinationDragging: (BOOL)aBool
- {
- // Change whether the view can behave as the destination of dragging.
- // Under certain circumstances you may want to not allow a drag into the
- // view.
- allowDestinationDragging = aBool;
- return self;
- }
-
-
-
- - (BOOL)allowDestinationDragging
- {
- // If YES is returned, the view can behave as the destination of
- // dragging, NO if it cannot.
- return allowDestinationDragging;
- }
-
-
-
- - (BOOL)acceptForeignDrag
- {
- // This method defines the behavior of the receiver. If YES is returned,
- // the view can behave as the destination of dragging from outside of the
- // application, NO if it cannot. Subclasses can override this to change
- // that behavior.
- return YES;
- }
-
-
-
- - (BOOL)acceptLocalDrag
- {
- // This method defines the behavior of the receiver. If YES is
- // returned, the view can behave as the destination of dragging from
- // within the application, NO if it cannot. Subclasses can override
- // this to change that behavior.
- return YES;
- }
-
-
-
- - (BOOL)acceptSelfDrag
- {
- // This method returns YES or NO, defining the behavior of the receiver.
- // If YES is returned, the view can receive data that was dragged out of
- // itself, NO if it cannot. Subclasses can override this to change that
- // behavior. If this method returns YES, then -acceptLocalDrag should
- // return YES as well.
- if ([self allowDestinationDragging] == NO)
- return NO;
-
- return YES;
- }
-
-
-
-
- - (BOOL)retainData
- {
- // This method returns YES or NO, defining the behavior of the receiver.
- // If YES is returned, the data being dragged from the view stays in the
- // view when dragged, NO if it does not. The default implementation
- // returns YES for all instances. Subclasses can override this to
- // change that behavior.
- return YES;
- }
-
-
-
- - (BOOL)shadowIncoming
- {
- // If YES is returned, when a view is able to accept a drag, the
- // dragged object will be shadowed within it. The default
- // implementation returns YES for all instances. Subclasses can
- // override this to change that behavior. THIS DOES NOT WORK YET.
- return shadowIncoming;
- }
-
- - setShadowIncoming:(BOOL)f
- { shadowIncoming=f;
- return self;
- }
-
- - (BOOL)dragImageIsMyImage
- { return dragImageIsMyImage;
- }
- - setDragImageIsMyImage:(BOOL)aDragImageIsMyImage
- { dragImageIsMyImage=aDragImageIsMyImage;
- return self;
- }
-
-
- - (NXColor)shadowColor
- {
- // This method returns the color used to created a dimmed appearance
- // for a destination image. The default is to return a partially
- // transparent gray. If you want a different appearance for shadowing,
- // you can override this method.
-
- NXColor shadowColor;
- shadowColor = NX_COLORLTGRAY;
- shadowColor = NXChangeAlphaComponent(shadowColor, 0.5);
- return shadowColor;
- }
-
-
-
- /*-------------------- methods to be the source of a dragging operation */
- #define STICKINESS 5.0
-
- - mouseDown: (NXEvent *)theEvent
- {
- // A source drag now will not begin until the mouse has been moved
- // more than STICKINESS pixels. This was sort of borrowed from Mike
- // Ferris's MODocumentWell class in the MOKit.
-
- NXEvent origEvent, *loopEvent;
- NXPoint zero = {0.0, 0.0};
- NXPoint origPoint, newLoc;
- NXCoord distance = 0.0;
- int oldMask;
-
- if (theImage == nil || [self allowSourceDragging] == NO)
- return [super mouseDown: theEvent];
-
- // if the overridden setupForSourceDrag returns YES continue
- if (!([self setupForSourceDrag] && [self dragImage]))
- return self;
-
- origPoint = theEvent->location;
- [self convertPoint: &origPoint fromView: nil];
- origEvent = *theEvent;
- oldMask = [ [self window] addToEventMask: NX_MOUSEDRAGGEDMASK];
-
- loopEvent = [NXApp getNextEvent:(NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK)];
- while (loopEvent->type != NX_MOUSEUP && distance < STICKINESS)
- {
- newLoc = loopEvent->location;
- [self convertPoint: &newLoc fromView: nil];
-
- // if we've gone at least STICKINESS units from the original
- // mousedown, start dragging our file.
- distance = sqrt(((newLoc.x - origPoint.x) * (newLoc.x - origPoint.x)) +
- ((newLoc.y - origPoint.y) * (newLoc.y - origPoint.y)));
-
- loopEvent = [NXApp getNextEvent:
- (NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK)];
- }
-
- [ [self window] setEventMask:oldMask];
- [self calculateDragPoint: &origPoint andOffset: &zero];
-
- // begin the drag session if the mouse moved far enough
- if (distance >= STICKINESS)
- {
- // send out the delegate message
- [self _sourceDragInitiated: self];
-
- sourceDragView = self;
- [self display];
- [self dragImage: [self dragImage] at: &origPoint offset: &zero
- event: &origEvent
- pasteboard: [self draggingPasteboard]
- source: self slideBack: [self slideback] ];
- [self cleanupAfterSourceDrag];
- [self display];
- }
-
- return self;
- }
-
-
-
- - cleanupAfterSourceDrag
- {
- // If we are not supposed to remember the data, then free the image
- // but on a delay. (It crashes after dragging in and out of the view
- // a few times if I use theImage = [theImage free] instead of the
- // delayed free. It seems to still need the image in the window's
- // drag methods.) Anyway, this seems to work fine this way.
-
- if (destinationDragView != self)
- // If the drag came from ourselves then don't free the image.
- if ([self retainData] == NO)
- [self setImage: nil];
-
- if (freeWhenDragDone == YES)
- [self perform: @selector(_freeImage:) with: [self dragImage]
- afterDelay: 0.0 cancelPrevious: NO];
- [self setDragImage: nil];
-
- sourceDragView = nil;
- destinationDragView = nil;
- return self;
- }
-
-
-
- - (BOOL)setupForSourceDrag
- {
- // A method that should be overridden in the subclass to put the
- // information on the desired pasteboard and select an image to drag.
- // If done successfully return YES for the drag to continue.
-
- if ([delegate respondsTo: @selector(setupForSourceDrag:)])
- { [delegate setupForSourceDrag:self];
- return YES;
- } else return NO;
- }
-
-
-
- - (BOOL)slideback
- {
- // Override this method if you like to change when images slide back to
- // their destination view when they aren't deposited in another view.
- // The default is to slide back if the view is retaining the data that
- // is being dragged.
- return [self retainData];
- }
-
-
-
- - draggingPasteboard
- {
- // Override this if you would like to use another pasteboard to do the
- // dragging.
- return [Pasteboard newName: NXDragPboard];
- }
-
-
-
- - calculateDragPoint: (NXPoint *)dragPoint andOffset: (NXPoint *)offset
- {
- // This method should be overridden if you want to have some control
- // on where the dragged image is first placed, and how far it is offset
- // from the original mousedown (dragPoint).
- // Making the dragPoint be the middle of the image is the default,
- // so it looks nice.
- dragPoint->x -= imageSize.width/2.0;
- dragPoint->y -= imageSize.height/2.0;
- return self;
- }
-
-
-
- - (NXDragOperation)draggingSourceOperationMaskForLocal:(BOOL)flag
- {
- return NX_DragOperationAll;
- }
-
-
-
- - draggedImage:(NXImage *)image endedAt:(NXPoint *)screenPoint
- deposited:(BOOL)flag
- {
- // Sends a "didFinishSourceDrag:" to the delegate if it responds.
- [self _sourceDragFinished: flag];
-
- return self;
- }
-
-
-
- /*-------------------- methods to be the destination of a dragging operation */
-
- - (NXDragOperation)draggingEntered: sender
- {
- if ([self allowDestinationDragging] == NO)
- return NX_DragOperationNone;
-
- if ([self acceptSelfDrag] == NO && [sender draggingSource] == self)
- return NX_DragOperationNone;
-
- if ([self acceptForeignDrag] == NO && [sender isDraggingSourceLocal] == NO)
- return NX_DragOperationNone;
-
- if ([self acceptLocalDrag] == NO && [sender isDraggingSourceLocal] == YES)
- return NX_DragOperationNone;
-
- // Send a "didInitiateDestinationDrag:" to the delegate
- [self _destinationDragInitiated: self];
-
- destinationDragView = self;
- // We will free the image in our cleanupAfterDestinationDrag method.
- destDragImage = [sender draggedImageCopy];
- [destDragImage setScalable: YES];
- [destDragImage getSize: &ddiSize];
- if ([self shadowIncoming] && [destDragImage lockFocus] == YES)
- {
- // Dim the image.
- NXSetColor([self shadowColor]);
- PScompositerect(0.0, 0.0, ddiSize.width, ddiSize.height, NX_SATOP);
- [destDragImage unlockFocus];
- }
-
- [self display];
-
- return NX_DragOperationCopy;
- }
-
-
-
- - (NXDragOperation)draggingUpdated: sender
- {
- return [super draggingUpdated: sender];
- }
-
-
-
- - draggingExited:sender
- {
- // Destination drag came to an end, but was not successful, so send a NO
- // to the delegate
- [self _destinationDragFinished: NO];
-
- // Free the dragged image we made a copy of.
- [self cleanupAfterDestinationDrag];
- destinationDragView = nil;
- [self displayFromOpaqueAncestor:(NXRect *)0 :0 :NO];
-
- return self;
- }
-
-
-
- - (BOOL)prepareForDragOperation:sender
- {
- return YES;
- }
-
-
-
- - (BOOL)performDragOperation:sender
- { if ([delegate respondsTo:@selector(takeDataFromPasteboard:)])
- return [delegate takeDataFromPasteboard:self];
-
- return YES;
- }
-
-
-
- - concludeDragOperation:sender
- {
- // Send the delegate a "didFinishDestinationDrag" message. If you override
- // this method make sure to call this so the delegate and action messages
- // will be sent.
-
- [self _destinationDragFinished: YES];
-
- // new - if we have a target/action combination, do it. ..shayman
- if ( target && action && [target respondsTo:action] )
- [target perform:action with:self];
-
- [self cleanupAfterDestinationDrag];
- if(![self shadowIncoming]) destinationDragView=nil; // "closed" icon again
- [self display];
- return self;
- }
-
-
-
- - cleanupAfterDestinationDrag
- {
- // Perform cleanup after the drag has completed.
- if (destDragImage != nil)
- destDragImage = [destDragImage free];
- ddiSize.width = 0.0;
- ddiSize.height = 0.0;
-
- return self;
- }
-
-
-
- /*-------------------- methods to display, and other useful stuff */
-
- - (BOOL)acceptsFirstMouse
- {
- return YES;
- }
-
-
-
- - (BOOL)shouldDelayWindowOrderingForEvent:(NXEvent *)theEvent
- {
- return YES;
- }
-
-
-
- - drawSelf: (const NXRect *)rects :(int)rectCount
- {
- NXImage *dispImage = nil;
- NXSize origSize;
- NXSize currSize;
- NXPoint offset;
- NXRect imageRect;
-
- switch (border)
- {
- case NX_GROOVE:
- NXDrawGroove (&bounds, rects);
- break;
-
- case NX_BEZEL:
- NXDrawGrayBezel(&bounds, rects);
- break;
-
- case NX_LINE:
- NXSetColor (NX_COLORLTGRAY);
- NXRectFill (&bounds);
- NXSetColor (NX_COLORBLACK);
- NXFrameRect (&bounds);
- break;
-
- case NX_NOBORDER:
- default:
- NXSetColor (NX_COLORLTGRAY);
- NXRectFill (&bounds);
- break;
- }
-
- // If there is no image, or we are supposed to give the illusion
- // that the data (image) was not retained then no reason to continue.
- // There seems to be alot of confusing choices where the view
- // should not show any images...
- if ((sourceDragView != nil && destinationDragView == sourceDragView &&
- [self shadowIncoming] == NO && [self retainData] == NO)
- || (destinationDragView != self && ([self image] == nil ||
- ([self retainData] == NO && self == sourceDragView))))
- return self;
-
- // Set so the image will not wipe the border (if any).
- imageRect.origin.x = NX_X(&bounds) + 2;
- imageRect.origin.y = NX_Y(&bounds) + 2;
- imageRect.size.width = NX_WIDTH(&bounds) - 4;
- imageRect.size.height = NX_HEIGHT(&bounds) - 4;
-
- // Choose which image should be displayed in the view. If we
- // are the destinationDragView and we are supposed to shadow
- // the image, then use the destDragImage.
- if ([self shadowIncoming] && destinationDragView == self &&
- destDragImage != nil)
- {
- dispImage = destDragImage;
- origSize.width = ddiSize.width;
- origSize.height = ddiSize.height;
- }
- else
- { // Otherwise display our image.
- if(destinationDragView == self && theAcceptingImage)
- dispImage = theAcceptingImage;
- else dispImage = theImage;
- origSize.width = imageSize.width;
- origSize.height = imageSize.height;
- }
- [dispImage getSize: &currSize];
-
- // Use different offsets depending on if image scaled or not.
- if (currSize.width > NX_WIDTH(&imageRect) ||
- currSize.height > NX_HEIGHT(&imageRect))
- {
- NXSize scaledSize;
- double xscale, yscale, scale;
-
- // scale the image and keep aspect ratio
- xscale = NX_WIDTH(&imageRect) / origSize.width;
- yscale = NX_HEIGHT(&imageRect) / origSize.height;
- scale = ((xscale < yscale) ? xscale : yscale);
- scaledSize.width = (origSize.width * scale); // - 2.0;
- scaledSize.height = (origSize.height * scale); // - 2.0;
-
- offset = imageRect.origin;
- offset.x += (NX_WIDTH(&imageRect) - scaledSize.width) / 2;
- offset.y += (NX_HEIGHT(&imageRect) - scaledSize.height) / 2;
- [dispImage setSize: &scaledSize];
-
- if (dispImage == destDragImage && [self shadowIncoming])
- // It seems like scaling the image makes it lose it's
- // dimmed look (that we applied in draggingEntered) so
- // do it again.
- if ([dispImage lockFocus] == YES)
- {
- NXSetColor([self shadowColor]);
- PScompositerect(0.0, 0.0, scaledSize.width,
- scaledSize.height, NX_SATOP);
- [dispImage unlockFocus];
- }
-
- }
- else
- {
- // no scaling needed
- offset = imageRect.origin;
- offset.x += (NX_WIDTH(&imageRect) - currSize.width) / 2.0;
- offset.y += (NX_HEIGHT(&imageRect) - currSize.height) / 2.0;
- }
-
- [dispImage composite: NX_SOVER toPoint: &offset];
- return self;
- }
-
-
-
- // Archiving methods
-
- - read:(NXTypedStream *)stream
- {
- int version;
- BOOL acceptForeignDrag, acceptLocalDrag;
- BOOL acceptSelfDrag, retainData;
-
- [super read:stream];
-
- version = NXTypedStreamClassVersion(stream, "MiscDragView");
-
- /*
- * **** Archiving: READ ME **** This code (and its analogue in write:) is
- * critical. When you bump MISC_DRAG_VIEW_VERSION, copy the whole _current_
- * case ("case MISC_DRAG_VIEW_VERSION: ... break;"), and duplicate it.
- * Change the "MISC_DRAG_VIEW_VERSION" in the old case to the OLD
- * (pre-bump) version number. Now, dork the "new current" version into
- * whatever you want. See how this code can now read EITHER version out of
- * the typed stream?
- *
- * If you are adding yet another version, leave the previous versions in
- * place. That way you can still read archived objects that are more than
- * one version old. Don't forget to take whatever actions are necessary to
- * harmonize those old values. For example, if you converted an "int" ivar
- * to "double", you'd need to (in the old version) to read the int version
- * into a temp variable, and convert it in to the double var. BJM 5/24/94
- */
- switch (version)
- {
- case 0:
- theImage = NXReadObject (stream);
- NXReadSize (stream, &imageSize);
- NXReadTypes (stream, "i", &border);
-
- delegate = NXReadObject (stream);
- NXReadTypes (stream, "c", &allowSourceDragging);
- NXReadTypes (stream, "c", &allowDestinationDragging);
- NXReadTypes (stream, "cc", &acceptForeignDrag, &acceptLocalDrag);
- NXReadTypes (stream, "cc", &acceptSelfDrag, &retainData);
- break;
-
- case 1:
- theImage = NXReadObject (stream);
- NXReadSize (stream, &imageSize);
- NXReadTypes (stream, "i", &border);
-
- delegate = NXReadObject (stream);
- NXReadTypes (stream, "c", &allowSourceDragging);
- NXReadTypes (stream, "c", &allowDestinationDragging);
- NXReadTypes (stream, "cc", &acceptForeignDrag, &acceptLocalDrag);
- NXReadTypes (stream, "cc", &acceptSelfDrag, &retainData);
- // Version 1 adds target/action stuff -- shayman
- NXReadTypes( stream, "@:", &target, &action );
- break;
-
- case 2:
- theImage = NXReadObject (stream);
- NXReadSize (stream, &imageSize);
- NXReadTypes (stream, "i", &border);
-
- delegate = NXReadObject (stream);
- NXReadTypes (stream, "c", &allowSourceDragging);
- NXReadTypes (stream, "c", &allowDestinationDragging);
- NXReadTypes( stream, "@:", &target, &action );
- break;
-
- case MISC_DRAG_VIEW_VERSION:
- theImage = NXReadObject (stream);
- NXReadSize (stream, &imageSize);
- NXReadTypes (stream, "i", &border);
-
- delegate = NXReadObject (stream);
- NXReadTypes (stream, "c", &allowSourceDragging);
- NXReadTypes (stream, "c", &allowDestinationDragging);
- NXReadTypes( stream, "@:", &target, &action );
-
- NXReadTypes (stream, "cc", &shadowIncoming,&dragImageIsMyImage); // new
- theAcceptingImage = NXReadObject (stream);
- break;
-
- default:
- NXLogError("[%s %s] - unknown version of %s in typed stream",
- [[self class] name], sel_getName(_cmd),
- [[MiscDragView class] name]);
- break;
- }
-
- return self;
- }
-
-
-
- - write:(NXTypedStream *)stream
- {
- BOOL acceptForeignDrag, acceptLocalDrag;
- BOOL acceptSelfDrag, retainData;
-
- [super write:stream];
-
- /*
- * **** Archiving: READ ME **** Home stretch. Now (just like read:)
- * duplicate the current case ("case MISC_DRAG_VIEW_VERSION: ... break;").
- * Once again, change the "MISC_DRAG_VIEW_VERSION" of the first one to the
- * OLD version number. Now adjust the new/current MISC_DRAG_VIEW_VERSION
- * (remember, you've bumped it) to the new way of writing vars. See how
- * this code (because the constant is in the switch statement) always
- * writes out ONLY the current version, but leaves the old version(s)
- * around to posterity. DO NOT DELETE THE OLD VERSIONS. Leave them to
- * clutter up the world. BJM 5/24/94
- */
- switch (MISC_DRAG_VIEW_VERSION)
- {
- case 0:
- NXWriteObject (stream, theImage);
- NXWriteSize (stream, &imageSize);
- NXWriteTypes (stream, "i", &border);
-
- NXWriteObjectReference (stream, delegate);
- NXWriteTypes (stream, "c", &allowSourceDragging);
- NXWriteTypes (stream, "c", &allowDestinationDragging);
- NXWriteTypes (stream, "cc", &acceptForeignDrag, &acceptLocalDrag);
- NXWriteTypes (stream, "cc", &acceptSelfDrag, &retainData);
- break;
-
- case 1:
- NXWriteObject (stream, theImage);
- NXWriteSize (stream, &imageSize);
- NXWriteTypes (stream, "i", &border);
-
- NXWriteObjectReference (stream, delegate);
- NXWriteTypes (stream, "c", &allowSourceDragging);
- NXWriteTypes (stream, "c", &allowDestinationDragging);
- NXWriteTypes (stream, "cc", &acceptForeignDrag, &acceptLocalDrag);
- NXWriteTypes (stream, "cc", &acceptSelfDrag, &retainData);
- // Version 1 adds support for target/action -- shayman
- NXWriteTypes (stream, "@:", &target, &action );
- break;
-
- case 2:
- NXWriteObject (stream, theImage);
- NXWriteSize (stream, &imageSize);
- NXWriteTypes (stream, "i", &border);
-
- NXWriteObjectReference (stream, delegate);
- NXWriteTypes (stream, "c", &allowSourceDragging);
- NXWriteTypes (stream, "c", &allowDestinationDragging);
- NXWriteTypes (stream, "@:", &target, &action );
- break;
-
- case MISC_DRAG_VIEW_VERSION:
- NXWriteObject (stream, theImage);
- NXWriteSize (stream, &imageSize);
- NXWriteTypes (stream, "i", &border);
-
- NXWriteObjectReference (stream, delegate);
- NXWriteTypes (stream, "c", &allowSourceDragging);
- NXWriteTypes (stream, "c", &allowDestinationDragging);
- NXWriteTypes (stream, "@:", &target, &action );
-
- NXWriteTypes (stream, "cc", &shadowIncoming,&dragImageIsMyImage); // new
- NXWriteObject(stream, theAcceptingImage);
- break;
-
- default:
- NXLogError("[%s %s] - unknown version of %s in typed stream",
- [[self class] name], sel_getName(_cmd), [[self class] name]);
- break;
- }
-
- return self;
- }
-
-
-
- - awake
- {
- [super awake];
- [self initDragTypes];
- if(theAcceptingImage) [self setShadowIncoming:NO];
-
- return self;
- }
-
- /*
- * new for version 1 - some basic target/action handling, and the idea
- * of a "stringValue" so that we can use this class just like various
- * Control objects.
- * steve hayman, aug 2 1994
- */
- - target { return target; }
- - setTarget:aTarget
- {
- target = aTarget;
- return self;
- }
- - (SEL)action { return action; }
- - setAction:(SEL)anAction
- {
- action = anAction;
- return self;
- }
-
- /*
- * these should be overridden in the appropriate way by subclasses -- shayman
- */
- - (const char *)stringValue { return NULL; }
- - setStringValue:(const char *)aValue { return self; }
- - takeStringValueFrom:sender
- {
- if ( [sender respondsTo:@selector(stringValue)] )
- return [self setStringValue: [sender stringValue]];
- return nil;
- }
-
- @end
-
-
-
- @interface MiscDragView (PrivateMethods)
-
- - _freeImage: image;
-
- @end
-
- @implementation MiscDragView (PrivateMethods)
-
- // Tries to fix the problem of freeing the image too early if the data
- // is not retained in the view. This method is called after a short
- // delay. Why isn't there a message perform:afterDelay:cancelPrevious?
- // Then you could just say [theImage perform:@selector(free)afterDelay..].
-
- - _freeImage: image
- {
- // Leak leak leak.... Uncomment at your own risk (probably OK if you
- // are not using any of the methods that use NXImage's +findImageNamed:
- //image = [image free];
- return self;
- }
-
-
- @end
-
-
- /***************************************************************************
- CHANGES:
-
- Bruce McKenzie (spuds@netcom.com) (aka BJM) on 5/24/94:
- 1) Added proper versioning/archiving
- 2) Reset variables so that class properly recognizes freed objects
- 3) Changed "- setImageByFilename: (char *)aFilename" to
- "- setImageByFilename: (const char *)aFilename
- Steve Hayman (shayman@Objectario.com)
- 4) Added Control's target/action paradigm. Added target and action
- ivars and target/setTarget:, action/setAction:,
- stringValue/setStringValue and takeStringValueFrom.
- Bill Shirley (Bill_Shirley@WilTel.com)
- 5) Made dragImage a class ivar since only one drag can take place
- at a time. Added dragImage/setDragImage: to set the var.
- 6) Removed the ivars acceptForeignDrag/localDrag/selfDrag/retainData
- and the methods to set them. (They have been put in the Backward
- compatability category) Each subclass of MiscDragView can
- make each choice for itself and you cannot change it at runtime.
- 7) Added initDragTypes method so you don't have to override both
- initFrame: and awake: in order to register your pasteboard types.
- 8) Added shadowIncoming/shadowOutgoing (note: they are not functional
- yet.)
- 9) Added slideback method to determine if an unsuccessfully dragged
- image should slideback to it's destination view.
- Todd Thomas (todd@avocado.supernet.ab.ca) on Sept. 20, 1994
- 10) Put all the delegate methods in a category and renamed all the
- methods sent to the delegate to be more inline with NeXT's.
- 11) Changed mouseDown so you have to move the mouse a little
- before a drag will start.
- Version 1.4: (Significant bug fixes and small additions) (Todd)
- 12) Fixed all (ok, so I'm being optimistic) the bugs related to
- non-retained views.
- 13) Added -cleanupAfterDestinationDrag method which must be called
- from your prepareForDragOperation: or performForDragOperation:
- if you decide to stop the drag operation (by returning NO). This
- frees a copy of the dragged image we made in draggingEntered:.
- 14) Changed method -cleanupImages to -cleanupAfterSourceDrag to
- be more in line with the newly created method in #13.
- 15) Added the ability of the destination drag views to show a
- "dimmed" image if it will accept the drag.
- 16) Just some general cleanup in drawSelf and some other methods.
- My personal changes:
- 1) Added accepting image outlet and supporting methods
- 2) dragImageIsMyImage flag introduced so that draggingImage
- can default to theImage
- 3) changed drawSelf to support an accepting image
- 4) setUpForDraggingOperation queries the delegate first
- 5) un-hardwiring shadowIncoming
- 6) Extended the Inspector so that icons can be set in IB
- 7) Providing a means for settin images by name
- 8) calculateDragPoint modified so that dragging looks nicer
- (as in MiscIconWell). Thought thas such a generic behaviour sooks nice
- in a generic class.
- 9) extended setDelegate in that it asks the delegate to provide an image
- (via - image method)
- 10) initDragTypes modified in that it first asks the delegate to load the types
- toDo 1) make freeing old theImage in setImage optional
- 2) supporting a Cell like Label
- 3) providing a delegate protocol
-
- ****************************************************************************/
-
-
-